#include "xmppcore/sessionnegotiant.h"
#include "xmppcore/iq.h"
#include "utils/uniqueid.h"
#include "xmppcore/errorparserfactory.h"
#include "xmppcore/errordetailsparserfactory.h"
#include "xmppcore/stanzaerror.h"
#include "xmppcore/iqparserfactory.h"
#include "xmppcore/stringtranslator.h"

namespace yoohoo_xmppcore {

SessionParsingFactory::SessionParsingFactory() {
	registerParser(new ErrorParserFactory(Error::ErrorTypeStanza), ProtocolRelation(ProtocolKey::NULL_PROTOCOL_KEY, StanzaError::PROTOCOL_KEY));
	registerParser(new StanzaErrorDetailsParserFactory, ProtocolRelation(StanzaError::PROTOCOL_KEY, StanzaError::ERROR_DETAIL_PROTOCOL_KEY));
	registerParser(new IqParserFactory, ProtocolRelation(ProtocolKey::NULL_PROTOCOL_KEY, Iq::PROTOCOL_KEY));
}

SessionNegotiant::SessionNegotiant(Connector* connector, QObject* parent) : Negotiant(connector, parent) {
}

void SessionNegotiant::negotiate() {
	Iq iq;

	iq.setId(yoohoo_utils::UniqueId::instance()->get());
	_iqId = iq.id();
	iq.setIqType(Iq::IqTypeSet);
	iq.setObj(new StringTranslator("<session xmlns='urn:ietf:params:xml:ns:xmpp-session'/>"));

	write(iq.toXml());
}

void SessionNegotiant::connectorReceived(QString xml) {
	XmppElement* element = parsingFactory()->parse(xml);
	
	if (!element) {
		emit negotiationError(UnknownNegotiationProtocolError);
		delete element;

		return;
	}

	StanzaError* error = dynamic_cast<StanzaError*>(element);
	if (error) {
		if ("internal-server-error" == error->definedCondition()) {
			emit sessionEstablishmentError(InternalServerError);
		} else if ("forbidden" == error->definedCondition()) {
			emit sessionEstablishmentError(ForbiddenError);
		} else if ("conflict" == error->definedCondition()) {
			emit sessionEstablishmentError(ConflictError);
		} else {
			emit negotiationError(UnknownNegotiationProtocolError);
		}

		delete error;
		return;
	}

	Iq* iq = dynamic_cast<Iq*>(element);
	if (!iq) {
		emit negotiationError(UnknownNegotiationProtocolError);
		delete element;

		return;
	}

	if (iq->iqType() != Iq::IqTypeResult) {
		emit negotiationError(UnknownNegotiationProtocolError);
	} else {
		emit success();
	}

	delete iq;

}

XmppParsingFactory* SessionNegotiant::parsingFactory() const {
	static SessionParsingFactory parsingFactory;

	return &parsingFactory;
}

}
